from ply.lex import TOKEN

_digit_sequence = r'[0-9]+'
_fractional_constant = r'([0-9]*\.[0-9]+)|([0-9]+\.)'
_exponent_part = r'[eE][+-]?' + _digit_sequence
_floating_literal = r'(' + _fractional_constant + '(' + _exponent_part + ')?[flFL]?)|(' + _digit_sequence + _exponent_part + '[flFL]?)'

_c_char = r'[0-9a-zA-Z]'
_c_char_sequence = _c_char + r'+'
_character_literal = r"'" + _c_char_sequence + r"'"

keywords = {
    'template'  : 'TEMPLATE',
    'typename'  : 'TYPENAME',
    'typedef'   : 'TYPEDEF',
    'friend'    : 'FRIEND',
    'enum'      : 'ENUM',
    # class key
    'class'     : 'CLASS',
    'struct'    : 'STRUCT',
    'union'     : 'UNION',
    # access specifier
    'public'    : 'PUBLIC',
    'protected' : 'PROTECTED',
    'private'   : 'PRIVATE',
    # simple type
    'char'      : 'CHAR',
    'wchar_t'   : 'WCHAR',
    'bool'      : 'BOOL',
    'short'     : 'SHORT',
    'int'       : 'INT',
    'long'      : 'LONG',
    'signed'    : 'SIGNED',
    'unsigned'  : 'UNSIGNED',
    'float'     : 'FLOAT',
    'double'    : 'DOUBLE',
    'void'      : 'VOID',
    # storage class specifier
    'auto'      : 'AUTO',
    'register'  : 'REGISTER',
    'static'    : 'STATIC',
    'extern'    : 'EXTERN',
    'mutable'   : 'MUTABLE',
    # function specifier
    'inline'    : 'INLINE',
    'virtual'   : 'VIRTUAL',
    'explicit'  : 'EXPLICIT',
    # cv qualifier
    'const'     : 'CONST',
    'volatile'  : 'VOLATILE',
}

tokens = ['ID', 'DECIMAL_LITERAL', 'FLOATING_LITERAL', 'CHARACTER_LITERAL'] + keywords.values() 

def t_newline(token):
    r'\n+'
    token.lexer.lineno += token.value.count("\n")

# http://ostermiller.org/findcomment.html 
def t_COMMENT(token):
    r'(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|(//.*)'
    pass

def t_ID(token):
    r'[a-zA-Z_][a-zA-Z_0-9]*'
    token.type = keywords.get(token.value, 'ID')
    return token

@TOKEN(_floating_literal)
def t_FLOATING_LITERAL(token):
    return token

@TOKEN(_character_literal)
def t_CHARACTER_LITERAL(token):
    return token

t_DECIMAL_LITERAL = r'[1-9][0-9]*[uUlL]*'

t_ignore = ' \t'
literals = r'0~:={}<>(),;*&[]'

def t_error(token):
    raise TypeError("Unknown text '%s'" % (token.value))

